#include "FileLog.h"
#include <string.h>
#include <errno.h>

namespace BASE{
	FileLog::FileLog():mLevel(LEVEL_WARN),pipeFd(-1),pipeFlag(false),ofs(NULL), backupTime(time(NULL)){
		start();
	}

	FileLog::~FileLog(){
		stopFile();
	}

	void FileLog::stopFile(){
		stop();
		flushFile();
		if (ofs.is_open()){
			ofs.close();
		}
		if (pipeFd > 0){
			close(pipeFd);
			pipeFd = -1;
		}

	}

	bool FileLog::initialize(const std::string & _fileName, const std::string & _pipeName, LOG_LEVEL _level){
		fileName = _fileName;
		pipeName = _pipeName;
		mLevel = _level;
		ofs.open(fileName.c_str(), std::ios::binary | std::ios::app);
		if (!ofs.is_open()){
			std::cerr << "open log file error," << strerror(errno) << std::endl;
			return false;
		}
		if (!openPipe()){
			std::cerr << "open pipe file error" << std::endl;
			return false;
		}
		backupTime = time(NULL);
		return true;
	}

	void FileLog::thread(){
		while(isRunning()){
			flushFile();
			sleep(1);
		}
	}

	SNodeBuf * FileLog::getNode(){
		Lock lock(bufMutex);
		pthread_t tid = pthread_self();
		SNodeBuf * nodeBuf;
		std::map<pthread_t, SNodeBuf*>::iterator iter = threadBuf.find(tid);
		if (iter == threadBuf.end()){
			nodeBuf = new SNodeBuf();
			threadBuf.insert(std::make_pair(tid, nodeBuf));
		}else{
			nodeBuf = iter->second;
		}
		return nodeBuf;
	}

	void FileLog::flushFile(){
		Lock lock(bufMutex);
		backupFile();
		if (buffer.empty() || !ofs){
			return;
		}
		//std::cout << "flush " << buffer << std::endl;
		ofs << buffer << std::flush;
		buffer.clear(); 
	}

	void FileLog::flushPipe(SNodeBuf * nodeBuf){
		write(pipeFd, nodeBuf->pipeBuf.c_str(), nodeBuf->pipeBuf.size());
		nodeBuf->pipeBuf = "";
	}

	void FileLog::appendBuffer(const std::string & buf){
		{
			Lock lock(bufMutex);
			buffer += buf;
		}
		//std::cout << "appendBuffer " << buffer << std::endl;
		if (buffer.size() >= LOG_BUFFER_SIZE){
			flushFile();
		}
	}

	void FileLog::backupFile(){
		if (Time::checkDay(backupTime)){
			return;
		}
		if (!ofs){
			return;
		}
		ofs.close();
		std::string dateStr = Time::getDateText(backupTime, "%Y-%m-%d");
		std::ostringstream ss;
		ss << fileName << dateStr << ".bak";
		rename(fileName.c_str(), ss.str().c_str());
		ofs.open(fileName.c_str(), std::ios::binary | std::ios::app);
	}

	bool FileLog::openPipe(){
		if (!pipeName.empty()){
			unlink(pipeName.c_str());
			mkfifo(pipeName.c_str(), 0777);
			int rdfd = open(pipeName.c_str(), O_RDONLY | O_NONBLOCK);
			pipeFd = open(pipeName.c_str(), O_WRONLY | O_NONBLOCK);
			if (pipeFd < 0){
				close(rdfd);
				std::cerr<< "open pipe error " << strerror(errno) << std::endl;
				return false;
			}else{
				close(rdfd);
			}
			signal(SIGPIPE, SIG_IGN);
			return true;
		}else{
			return false;
		}
	}
}
